/*
 * Copyright (c) 2019-2022. Alexey Antipin and others.
 * https://github.com/Evreke/warships
 *
 * Licensed under the Apache License 2.0
 */

package ru.evreke.ui

import Board
import BoardPayload
import ClientMessage
import GamePayload
import GenericMessage
import GenericServerMessage
import Message
import ServerMessage
import androidx.compose.runtime.mutableStateOf
import client
import io.ktor.client.plugins.websocket.*
import io.ktor.http.*
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.consumeEach
import org.jetbrains.compose.web.css.Style
import org.jetbrains.compose.web.dom.H1
import org.jetbrains.compose.web.dom.Text
import org.jetbrains.compose.web.renderComposable
import ru.evreke.ui.style.AppStylesheet

val scope = MainScope()
val messagingScope = CoroutineScope(CoroutineName("websocket"))
val sendChannelScope = CoroutineScope(CoroutineName("sendChannel"))

val gameToPlayerBoard = mutableStateOf<Map<String, Map<String, Board>>>(mapOf())
val pendingGames = mutableStateOf(listOf<String>())
val sendChanel = Channel<ClientMessage>()

suspend fun main() {

    val socket = messagingScope.async {
        client.webSocketSession(
            method = HttpMethod.Get,
            host = "127.0.0.1",
            port = 8080,
            path = "/ws"
        )
    }.await()

    // Receiving messages from channel and send them to websocket
    initOutgoingMessageLoop(socket)
    // Receiving messages from websocket and handle them
    initIncomingMessageLoop(socket)


    renderComposable(rootElementId = "root") {
        Style(AppStylesheet)

        H1 {
            Text("Warships")
        }

        Games(pendingGames, sendChanel, sendChannelScope)

        Board(
            gameToPlayerBoard,
            sendChanel,
            sendChannelScope
        )

        CustomButton("Init game") {
            scope.launch {
                sendChanel.send(GenericMessage(Message.INIT))
            }
        }
        CustomButton("List games") {
            scope.launch {
                sendChanel.send(GenericMessage(Message.JOIN))
            }
        }
    }
}

private fun initOutgoingMessageLoop(socket: DefaultClientWebSocketSession) {
    messagingScope.launch {
        while (true) {
            sendChanel.consumeEach {
                console.log("Sending message $it")
                socket.sendSerialized(it)
                console.log("Sended")
            }
        }
    }
}

private fun initIncomingMessageLoop(socket: DefaultClientWebSocketSession) {
    messagingScope.launch {
        while (true) {
            when (val message = socket.receiveDeserialized<ServerMessage>()) {
                is GenericServerMessage -> {
                    when (message.payload) {
                        is BoardPayload -> {
                            gameToPlayerBoard.value = mapOf(message.payload.id to message.payload.board)
                        }

                        is GamePayload -> {
                            pendingGames.value = message.payload.ids
                            pendingGames.value.forEach {
                                console.log(it)
                            }
                        }
                    }
                }
            }
        }
    }
}
